<html>
<head>
<title>TeenyDT - Online USB Descriptor Generator</title>
<style type="text/css" media="screen">
    #luaDesc { 
        height: 800px ;
        width: 600px ;
    }
    #result{
        height: 800px ;
        width: 900px ;
    }
</style>

<script src="fengari-web.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.6/ace.js" integrity="sha256-CVkji/u32aj2TeC+D13f7scFSIfphw2pmu4LaKWMSY8=" crossorigin="anonymous"></script>

</head>
<body>
<h1> TeenyDT - Online USB Descriptor Generator</h1>

<p> A lua based USB descriptor generate tool, source code on <a href="https://github.com/teenydt/teenydt.github.io">GitHub</a>.
How to use the descriptor? <a href="https://github.com/xtoolbox/TeenyUSB/tree/master/demo/composite">Demo for TeenyUSB</a>, 
<a href="https://github.com/teenydt/teenydt.github.io/tree/master/demo/opencm3">Demo for libOpenCM3</a>.</p>

<table border="0">
<tr>
<td>
<h3>Lua format descriptor</h3>
</td>

<td>
<h3>==></h3>
</td>

<td>
<h3>C Code</h3>
</td>

</tr>

<tr>
    <td>
        USB Core Type: <select id="mcuSelect" onchange="changeMCU();">
                <option selected="selected" value="[7,1024]">STM32F0xx</option>
                <option value="[7,512]">STM32F10x_FS</option>
                <option value="[3,1280]">STM32F10x_OTG_FS</option>
                <option value="[3,1280]">STM32F2xx_OTG_FS</option>
                <option value="[5,4096]">STM32F2xx_OTG_HS</option>
                <option value="[7,512]">STM32F3xx_BC_FS</option>
                <option value="[7,512]">STM32F373_XX_FS</option>
                <option value="[7,1024]">STM32F3xx_DE_FS</option>
                <option value="[3,1280]">STM32F4xx_OTG_FS</option>
                <option value="[5,4096]">STM32F4xx_OTG_HS</option>
                <option value="[5,1280]">STM32F7xx_OTG_FS</option>
                <option value="[8,4096]">STM32F7xx_OTG_HS</option>
                <option value="[8,1280]">STM32H7xx_OTG_FS</option>
                <option value="[8,4096]">STM32H7xx_OTG_HS</option>
        </select>
        MaxEp:<input type="text" id="MaxEp" value="7" style="width:20px;" />
        MaxMem:<input type="text" id="MaxMem" value="1024" style="width:40px;"/>
        <button id="downloadDesc" onClick="downloadDesc();">Download Desc</button>
    </td>
    <td>

    </td>
    <td>
        File name:<input type="text" id="fileName" value=""  readonly/>
        <button id="downloadCode" onClick="downloadCode();">Download Code</button>
    </td>
</tr>

<tr>
<td>
<div id="luaDesc">return Device {
    strManufacturer = "TeenyUSB",
    strProduct = "TeenyUSB Composite DEMO",
    strSerial = "TUSB123456",
    idVendor = 0x0483,
    idProduct = 0x0011,
    prefix = "COMP",
    Config {
        USB_HID{
            ReadEp = EndPoint(IN(2),  Interrupt, 16),
            WriteEp = EndPoint(OUT(2), Interrupt, 16),
            report = HID_InOut(16),
        },
        CDC_ACM{
            EndPoint(IN(8),  Interrupt, 16),
            EndPoint(IN(1), BulkDouble, 32),
            EndPoint(OUT(1),  BulkDouble, 32),
        },
        Interface{
            WCID=WinUSB,
            strInterface = "TeenyUSB WinUSB",
            GUID="{1D4B2365-4749-48EA-B38A-7C6FDDDD7E26}",
            EndPoint(IN(3),  BulkDouble, 32),
            EndPoint(OUT(3), BulkDouble, 32),
        },
        Interface{
            bInterfaceClass = 0x08,        -- MSC
            bInterfaceSubClass = 0x06,     -- SCSI
            bInterfaceProtocol = 0x50,     -- BOT
            EndPoint(IN(4),  BulkDouble, 64),
            EndPoint(OUT(4), BulkDouble, 64),
        },
   }
}
</div>

</td>

<td>
<p>Sample Desc</p>
<p>
</p>
<select id="exampleDesc" onchange="changeDesc();">
</select>
<p>

<br><br>
<p><a href="https://github.com/teenydt/teenydt.github.io/blob/master/sample_desc/readme.md#add-sample">Add sample</a></p>
<br><br>

<button id="idTeenyC" onClick="toTeenyC();">==> TeenyUSB .c</button>
</p>

<p>
<button id="idTeenyH" onClick="toTeenyH();">==> TeenyUSB .h</button>
</p>
<p>
<button id="idOpenCM3C" onClick="toOpenCM3C();">==> OpenCM3 .c</button>
</p>

<p>
<button id="idOpenCM3H" onClick="toOpenCM3H();">==> OpenCM3 .h</button>
</p>

<p>Color Style<p/>

<p>
<select id="theme" onchange="changeTheme();"><optgroup label="Bright"><option value="ace/theme/chrome">Chrome</option><option value="ace/theme/clouds">Clouds</option><option value="ace/theme/crimson_editor">Crimson Editor</option><option value="ace/theme/dawn">Dawn</option><option value="ace/theme/dreamweaver">Dreamweaver</option><option value="ace/theme/eclipse">Eclipse</option><option value="ace/theme/github">GitHub</option><option value="ace/theme/iplastic">IPlastic</option><option value="ace/theme/solarized_light">Solarized Light</option><option value="ace/theme/textmate">TextMate</option><option value="ace/theme/tomorrow">Tomorrow</option><option value="ace/theme/xcode">XCode</option><option value="ace/theme/kuroir">Kuroir</option><option value="ace/theme/katzenmilch">KatzenMilch</option><option value="ace/theme/sqlserver">SQL Server</option></optgroup><optgroup label="Dark"><option value="ace/theme/ambiance">Ambiance</option><option value="ace/theme/chaos">Chaos</option><option value="ace/theme/clouds_midnight">Clouds Midnight</option><option value="ace/theme/dracula">Dracula</option><option value="ace/theme/cobalt">Cobalt</option><option value="ace/theme/gruvbox">Gruvbox</option><option value="ace/theme/gob">Green on Black</option><option value="ace/theme/idle_fingers">idle Fingers</option><option value="ace/theme/kr_theme">krTheme</option><option value="ace/theme/merbivore">Merbivore</option><option value="ace/theme/merbivore_soft">Merbivore Soft</option><option value="ace/theme/mono_industrial">Mono Industrial</option><option value="ace/theme/monokai">Monokai</option><option value="ace/theme/pastel_on_dark">Pastel on dark</option><option value="ace/theme/solarized_dark">Solarized Dark</option><option value="ace/theme/terminal">Terminal</option><option value="ace/theme/tomorrow_night">Tomorrow Night</option><option value="ace/theme/tomorrow_night_blue">Tomorrow Night Blue</option><option value="ace/theme/tomorrow_night_bright">Tomorrow Night Bright</option><option value="ace/theme/tomorrow_night_eighties">Tomorrow Night 80s</option><option value="ace/theme/twilight">Twilight</option><option value="ace/theme/vibrant_ink">Vibrant Ink</option></optgroup></select>
</p>

<br><br><br><br><br><br><br><br><br><br><br><br><br><br>

</td>

<td>
<div id="result"></div>
</td>

</tr>


</table>
<p>Log</p>
<p><textarea id="logInfo" style="width:800px;height:80px;" readonly></textarea></p>

<p>The code editor is <a href="https://ace.c9.io/">ACE</a></p>
<p>The Lua parser is <a href="https://fengari.io/">fengari</a></p>

<script type="application/lua">
    local js = require("js")
    local logText = js.global.document:getElementById("logInfo")

    require("usb_teeny_desc")
    require("usb_opencm3_desc")
    local fileHeader = [[
/////////////////////////////////////////////////////////////
//// Auto generate by TeenyDT, http://dt.tusb.org
/////////////////////////////////////////////////////////////
]]
    function gen_tc(src)
        local desc = load(src)()
        return fileHeader .. Generate_TeenyUSB_desc(desc)
    end
    
    function gen_th(src, maxep, maxmem)
        local desc = load(src)()
        return fileHeader .. Generate_TeenyUSB_header(desc, maxep or 9, maxmem or 4096)
    end
    
    function gen_oc(src)
        local desc = load(src)()
        return fileHeader .. Generate_LibOpenCM3_desc(desc)
    end
    
    function gen_oh(src, maxep, maxmem)
        local desc = load(src)()
        return fileHeader .. Generate_LibOpenCM3_header(desc, maxep or 9, maxmem or 4096)
    end
    
    
    io = {}
    io.write = function(...)
        local s = ""
        local sep = ""
        for i,v in ipairs({...}) do
            s = s .. sep .. v
            sep = " "
        end
        logText.value = logText.value .. s
        print(...)
    end
    
</script>

<script>
    var logText = document.getElementById("logInfo");
    var sampleDesc = []
    function debug(message) {
        logText.value += message + "\n";
        logText.scrollTop = logText.scrollHeight;
    }

    function clearLog() {
        logText.value = "";
    }
    var luaEditor = ace.edit("luaDesc",{
        theme: "ace/theme/github",
        mode:  "ace/mode/lua",
        maxLines: 50,
        minLines: 50,
    });
    
    var cEditor = ace.edit("result", {
        theme: "ace/theme/github",
        mode:  "ace/mode/c_cpp",
        maxLines: 50,
        minLines: 50,
        readOnly : true,
    });
    
    document.getElementById("theme").value = "ace/theme/github";
    function changeTheme(){
        var t = document.getElementById("theme").value;
        luaEditor.setTheme(t);
        cEditor.setTheme(t);
    }

    function changeMCU(){
        var t = document.getElementById("mcuSelect").value;
        var r = JSON.parse(t);
        document.getElementById("MaxEp").value = r[0];
        document.getElementById("MaxMem").value = r[1];
    }
    
    var lastAction = null;
    
    function toTeenyC(){
        document.getElementById("fileName").value = "teeny_usb_desc.c";
        clearLog();
        cEditor.setValue( fengari.load('return gen_tc([==[' + luaEditor.getValue() + ']==])' )()  );
        cEditor.clearSelection();
        lastAction = toTeenyC;
    }
    function toTeenyH(){
        document.getElementById("fileName").value = "teeny_usb_desc.h";
        var param = ',' + document.getElementById("MaxEp").value + ',' + document.getElementById("MaxMem").value
        clearLog();
        cEditor.setValue( fengari.load('return gen_th([==[' + luaEditor.getValue() + ']==]'+param+')' )()  );
        cEditor.clearSelection();
        lastAction = toTeenyH;
    }
    function toOpenCM3C(){
        document.getElementById("fileName").value = "opencm3_usb_init.c";
        clearLog();
        cEditor.setValue( fengari.load('return gen_oc([==[' + luaEditor.getValue() + ']==])' )()  );
        cEditor.clearSelection();
        lastAction = toOpenCM3C;
    }
    function toOpenCM3H(){
        document.getElementById("fileName").value = "opencm3_usb_init.h";
        var param = ',' + document.getElementById("MaxEp").value + ',' + document.getElementById("MaxMem").value
        clearLog();
        cEditor.setValue( fengari.load('return gen_oh([==[' + luaEditor.getValue() + ']==]'+param+')' )()  );
        cEditor.clearSelection();
        lastAction = toOpenCM3H;
    }
    
    var saveData = (function () {
        var a = document.createElement("a");
        document.body.appendChild(a);
        a.style = "display: none";
        return function (data, fileName) {
            var blob = new Blob([data], {type: "text/plain"});
            var url = window.URL.createObjectURL(blob);
            a.href = url;
            a.download = fileName;
            a.click();
            //window.URL.revokeObjectURL(url);
        };
    }());

    function downloadDesc(){
        var t = document.getElementById("exampleDesc").value;
        saveData(luaEditor.getValue(), t+"_desc.lua");
    }
    function downloadCode(){
        var fn = document.getElementById("fileName").value
        if(fn != ""){
            saveData(cEditor.getValue(), fn);
        }
    }
    
    function changeDesc(){
        var t = document.getElementById("exampleDesc").value;
        if(sampleDesc[t]){
            if(sampleDesc[t].content){
                luaEditor.setValue( sampleDesc[t].content );
                luaEditor.clearSelection();
                if(lastAction){
                    lastAction();
                }
            }else{
                luaEditor.setValue( "-- content not ready " + t );
            }
        }else{
            luaEditor.setValue( "-- content not exist for " + t );
        }
    }
    
    
    function getText(url, action, param){
        var xmlhttp;
        if (window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
        } else {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange = function(){
            if (xmlhttp.readyState == XMLHttpRequest.DONE ) 
            {
               if(xmlhttp.status == 200){
                   action(xmlhttp.responseText, param);
               }
               else {
                   console.log("Fail to load sample descriptor at " + url);
               }
            }
        }
        xmlhttp.open("GET", url, true);
        xmlhttp.send();
    }
    
    function parseDescContent(content, name){
        sampleDesc[name].content = content;
    }
    
    function parseDescriptor(desc, name){
        var sel = document.getElementById("exampleDesc")
        var res = desc.match(/\{\s*File\s*\=\s*\"([^\"]+)\"\s*,\s*Description\s*\=\s*\"([^\"]+)\"[\s,]*\}/g)
        for(var i=0; i<res.length;i++){
            var t = res[i].replace("File",'"File"').replace("Description",'"Description"').replace(/\=/g,":")
            t = JSON.parse(t);
            sampleDesc[t.File] = { Desc:t.Description };
            sel.options[i] = new Option(t.Description, t.File);
            getText("sample_desc/"+t.File+".lua", parseDescContent, t.File);
        }        
    }
    getText("sample_desc/descriptor.lua", parseDescriptor, "desc")
    
</script>


</body>
</html>